home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / audio_output / output.c < prev   
C/C++ Source or Header  |  2003-04-07  |  14KB  |  340 lines

  1. /*****************************************************************************
  2.  * output.c : internal management of output streams for the audio output
  3.  *****************************************************************************
  4.  * Copyright (C) 2002 VideoLAN
  5.  * $Id: output.c,v 1.36 2003/02/08 17:26:00 massiot Exp $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>                            /* calloc(), malloc(), free() */
  28. #include <string.h>
  29.  
  30. #include <vlc/vlc.h>
  31.  
  32. #include "audio_output.h"
  33. #include "aout_internal.h"
  34.  
  35. /*****************************************************************************
  36.  * aout_OutputNew : allocate a new output and rework the filter pipeline
  37.  *****************************************************************************
  38.  * This function is entered with the mixer lock.
  39.  *****************************************************************************/
  40. int aout_OutputNew( aout_instance_t * p_aout,
  41.                     audio_sample_format_t * p_format )
  42. {
  43.     /* Retrieve user defaults. */
  44.     char * psz_name = config_GetPsz( p_aout, "aout" );
  45.     int i_rate = config_GetInt( p_aout, "aout-rate" );
  46.     vlc_value_t val;
  47.  
  48.     memcpy( &p_aout->output.output, p_format, sizeof(audio_sample_format_t) );
  49.     if ( i_rate != -1 )
  50.         p_aout->output.output.i_rate = i_rate;
  51.     aout_FormatPrepare( &p_aout->output.output );
  52.  
  53.     vlc_mutex_lock( &p_aout->output_fifo_lock );
  54.  
  55.     /* Find the best output plug-in. */
  56.     p_aout->output.p_module = module_Need( p_aout, "audio output",
  57.                                            psz_name );
  58.     if ( psz_name != NULL ) free( psz_name );
  59.     if ( p_aout->output.p_module == NULL )
  60.     {
  61.         msg_Err( p_aout, "no suitable aout module" );
  62.         vlc_mutex_unlock( &p_aout->output_fifo_lock );
  63.         return -1;
  64.     }
  65.  
  66.     if ( var_Type( p_aout, "audio-channels" ) ==
  67.              (VLC_VAR_STRING | VLC_VAR_HASCHOICE) )
  68.     {
  69.         /* The user may have selected a different channels configuration. */
  70.         var_Get( p_aout, "audio-channels", &val );
  71.  
  72.         if ( !strcmp( val.psz_string, _("Reverse stereo") ) )
  73.         {
  74.             p_aout->output.output.i_original_channels |=
  75.                                         AOUT_CHAN_REVERSESTEREO;
  76.         }
  77.         else if ( !strcmp( val.psz_string, _("Stereo") ) )
  78.         {
  79.             p_aout->output.output.i_original_channels =
  80.                 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  81.         }
  82.         else if ( !strcmp( val.psz_string, _("Left") ) )
  83.         {
  84.             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
  85.         }
  86.         else if ( !strcmp( val.psz_string, _("Right") ) )
  87.         {
  88.             p_aout->output.output.i_original_channels = AOUT_CHAN_RIGHT;
  89.         }
  90.         else if ( !strcmp( val.psz_string, _("Dolby Surround") ) )
  91.         {
  92.             p_aout->output.output.i_original_channels
  93.                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO;
  94.         }
  95.         free( val.psz_string );
  96.     }
  97.     else if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER
  98.               && (p_aout->output.output.i_original_channels
  99.                    & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
  100.     {
  101.         /* Mono - create the audio-channels variable. */
  102.         var_Create( p_aout, "audio-channels", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
  103.         val.psz_string = _("Stereo");
  104.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val );
  105.         val.psz_string = _("Left");
  106.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val );
  107.         val.psz_string = _("Right");
  108.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val );
  109.         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
  110.         {
  111.             /* Go directly to the left channel. */
  112.             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
  113.             val.psz_string = _("Left");
  114.             var_Set( p_aout, "audio-channels", val );
  115.         }
  116.         var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
  117.                          NULL );
  118.     }
  119.     else if ( p_aout->output.output.i_physical_channels ==
  120.                (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
  121.                 && (p_aout->output.output.i_original_channels &
  122.                      (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
  123.     {
  124.         /* Stereo - create the audio-channels variable. */
  125.         var_Create( p_aout, "audio-channels", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
  126.         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
  127.         {
  128.             val.psz_string = _("Dolby Surround");
  129.         }
  130.         else
  131.         {
  132.             val.psz_string = _("Stereo");
  133.         }
  134.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val );
  135.         val.psz_string = _("Left");
  136.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val );
  137.         val.psz_string = _("Right");
  138.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val );
  139.         val.psz_string = _("Reverse stereo");
  140.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val );
  141.         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
  142.         {
  143.             /* Go directly to the left channel. */
  144.             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
  145.             val.psz_string = _("Left");
  146.             var_Set( p_aout, "audio-channels", val );
  147.         }
  148.         var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
  149.                          NULL );
  150.     }
  151.     val.b_bool = VLC_TRUE;
  152.     var_Set( p_aout, "intf-change", val );
  153.  
  154.     aout_FormatPrepare( &p_aout->output.output );
  155.  
  156.     /* Prepare FIFO. */
  157.     aout_FifoInit( p_aout, &p_aout->output.fifo,
  158.                    p_aout->output.output.i_rate );
  159.  
  160.     vlc_mutex_unlock( &p_aout->output_fifo_lock );
  161.  
  162.     aout_FormatPrint( p_aout, "output", &p_aout->output.output );
  163.  
  164.     /* Calculate the resulting mixer output format. */
  165.     memcpy( &p_aout->mixer.mixer, &p_aout->output.output,
  166.             sizeof(audio_sample_format_t) );
  167.     if ( !AOUT_FMT_NON_LINEAR(&p_aout->output.output) )
  168.     {
  169.         /* Non-S/PDIF mixer only deals with float32 or fixed32. */
  170.         p_aout->mixer.mixer.i_format
  171.                      = (p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU) ?
  172.                         VLC_FOURCC('f','l','3','2') :
  173.                         VLC_FOURCC('f','i','3','2');
  174.         aout_FormatPrepare( &p_aout->mixer.mixer );
  175.     }
  176.     else
  177.     {
  178.         p_aout->mixer.mixer.i_format = p_format->i_format;
  179.     }
  180.  
  181.     aout_FormatPrint( p_aout, "mixer", &p_aout->output.output );
  182.  
  183.     /* Create filters. */
  184.     if ( aout_FiltersCreatePipeline( p_aout, p_aout->output.pp_filters,
  185.                                      &p_aout->output.i_nb_filters,
  186.                                      &p_aout->mixer.mixer,
  187.                                      &p_aout->output.output ) < 0 )
  188.     {
  189.         msg_Err( p_aout, "couldn't set an output pipeline" );
  190.         module_Unneed( p_aout, p_aout->output.p_module );
  191.         return -1;
  192.     }
  193.  
  194.     /* Prepare hints for the buffer allocator. */
  195.     p_aout->mixer.output_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  196.     p_aout->mixer.output_alloc.i_bytes_per_sec
  197.                         = p_aout->mixer.mixer.i_bytes_per_frame
  198.                            * p_aout->mixer.mixer.i_rate
  199.                            / p_aout->mixer.mixer.i_frame_length;
  200.  
  201.     aout_FiltersHintBuffers( p_aout, p_aout->output.pp_filters,
  202.                              p_aout->output.i_nb_filters,
  203.                              &p_aout->mixer.output_alloc );
  204.  
  205.     p_aout->output.b_error = 0;
  206.     return 0;
  207. }
  208.  
  209. /*****************************************************************************
  210.  * aout_OutputDelete : delete the output
  211.  *****************************************************************************
  212.  * This function is entered with the mixer lock.
  213.  *****************************************************************************/
  214. void aout_OutputDelete( aout_instance_t * p_aout )
  215. {
  216.     if ( p_aout->output.b_error )
  217.     {
  218.         return;
  219.     }
  220.  
  221.     module_Unneed( p_aout, p_aout->output.p_module );
  222.  
  223.     aout_FiltersDestroyPipeline( p_aout, p_aout->output.pp_filters,
  224.                                  p_aout->output.i_nb_filters );
  225.     aout_FifoDestroy( p_aout, &p_aout->output.fifo );
  226.  
  227.     p_aout->output.b_error = VLC_TRUE;
  228. }
  229.  
  230. /*****************************************************************************
  231.  * aout_OutputPlay : play a buffer
  232.  *****************************************************************************
  233.  * This function is entered with the mixer lock.
  234.  *****************************************************************************/
  235. void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
  236. {
  237.     aout_FiltersPlay( p_aout, p_aout->output.pp_filters,
  238.                       p_aout->output.i_nb_filters,
  239.                       &p_buffer );
  240.  
  241.     vlc_mutex_lock( &p_aout->output_fifo_lock );
  242.     aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
  243.     p_aout->output.pf_play( p_aout );
  244.     vlc_mutex_unlock( &p_aout->output_fifo_lock );
  245. }
  246.  
  247. /*****************************************************************************
  248.  * aout_OutputNextBuffer : give the audio output plug-in the right buffer
  249.  *****************************************************************************
  250.  * If b_can_sleek is 1, the aout core functions won't try to resample
  251.  * new buffers to catch up - that is we suppose that the output plug-in can
  252.  * compensate it by itself. S/PDIF outputs should always set b_can_sleek = 1.
  253.  * This function is entered with no lock at all :-).
  254.  *****************************************************************************/
  255. aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
  256.                                        mtime_t start_date,
  257.                                        vlc_bool_t b_can_sleek )
  258. {
  259.     aout_buffer_t * p_buffer;
  260.  
  261.     vlc_mutex_lock( &p_aout->output_fifo_lock );
  262.  
  263.     p_buffer = p_aout->output.fifo.p_first;
  264.     while ( p_buffer && p_buffer->start_date < mdate() )
  265.     {
  266.         msg_Dbg( p_aout, "audio output is too slow ("I64Fd"), "
  267.                  "trashing "I64Fd"us", mdate() - p_buffer->start_date,
  268.                  p_buffer->end_date - p_buffer->start_date );
  269.         p_buffer = p_buffer->p_next;
  270.         aout_BufferFree( p_aout->output.fifo.p_first );
  271.         p_aout->output.fifo.p_first = p_buffer;
  272.     }
  273.  
  274.     if ( p_buffer == NULL )
  275.     {
  276.         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
  277.  
  278. #if 0 /* This is bad because the audio output might just be trying to fill
  279.        * in it's internal buffers. And anyway, it's up to the audio output
  280.        * to deal with this kind of starvation. */
  281.  
  282.         /* Set date to 0, to allow the mixer to send a new buffer ASAP */
  283.         aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
  284.         if ( !p_aout->output.b_starving )
  285.             msg_Dbg( p_aout,
  286.                  "audio output is starving (no input), playing silence" );
  287.         p_aout->output.b_starving = 1;
  288. #endif
  289.  
  290.         vlc_mutex_unlock( &p_aout->output_fifo_lock );
  291.         return NULL;
  292.     }
  293.  
  294.     /* Here we suppose that all buffers have the same duration - this is
  295.      * generally true, and anyway if it's wrong it won't be a disaster. */
  296.     if ( p_buffer->start_date > start_date
  297.                          + (p_buffer->end_date - p_buffer->start_date) )
  298.     {
  299.         vlc_mutex_unlock( &p_aout->output_fifo_lock );
  300.         if ( !p_aout->output.b_starving )
  301.             msg_Dbg( p_aout, "audio output is starving ("I64Fd"), "
  302.                      "playing silence", p_buffer->start_date - start_date );
  303.         p_aout->output.b_starving = 1;
  304.         return NULL;
  305.     }
  306.  
  307.     p_aout->output.b_starving = 0;
  308.  
  309.     if ( !b_can_sleek &&
  310.           ( (p_buffer->start_date - start_date > AOUT_PTS_TOLERANCE)
  311.              || (start_date - p_buffer->start_date > AOUT_PTS_TOLERANCE) ) )
  312.     {
  313.         /* Try to compensate the drift by doing some resampling. */
  314.         int i;
  315.         mtime_t difference = start_date - p_buffer->start_date;
  316.         msg_Warn( p_aout, "output date isn't PTS date, requesting "
  317.                   "resampling ("I64Fd")", difference );
  318.  
  319.         vlc_mutex_lock( &p_aout->input_fifos_lock );
  320.         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
  321.         {
  322.             aout_fifo_t * p_fifo = &p_aout->pp_inputs[i]->fifo;
  323.  
  324.             aout_FifoMoveDates( p_aout, p_fifo, difference );
  325.         }
  326.  
  327.         aout_FifoMoveDates( p_aout, &p_aout->output.fifo, difference );
  328.         vlc_mutex_unlock( &p_aout->input_fifos_lock );
  329.     }
  330.  
  331.     p_aout->output.fifo.p_first = p_buffer->p_next;
  332.     if ( p_buffer->p_next == NULL )
  333.     {
  334.         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
  335.     }
  336.  
  337.     vlc_mutex_unlock( &p_aout->output_fifo_lock );
  338.     return p_buffer;
  339. }
  340.